from enum import Enum
import copy
from logzero import logger as log

class CacheType(Enum):
    PARAMETER='parameter'
    UN_PARAMETER='un-parameter'

class Cache(object):
    '''
    [
        {
            key:'cache_user',
            func:query_user,
            *row_func:query_glory_of_user,
            type:CacheType.DICT,
        },
    ]
    '''
    def __init__(self,cache_key,cache_type,func,row_func=None,sep='_@_'):
        self.__cache_config={cache_key:(cache_type,func,row_func)}
        self.__cache={}
        self.__sep=sep
    
    def reg(self,cache_key,cache_type,func,row_func=None):
        self.__cache_config[cache_key]=(cache_type,func,row_func)

    # def __call(self,func,*opts):
    #     if len(opts)>0:
    #         return func(*opts)
    #     return func(*opts)

    def __get(self,key,*opts):
        cache=self.__cache.get(key)
        cc=self.__cache_config.get(key)
        if cc:
            ct,fc,rfc=cc
            if cache:
                datakey=self.__sep.join(opts)
                log.debug('HIT - %s-%s'%(key,datakey))
                if ct==CacheType.PARAMETER:
                    v=cache.get(datakey)
                    v=v if v else fc(*opts)
                    cache[datakey]=v
                    return copy.deepcopy(v)
                else:
                    return copy.deepcopy(cache)
            else:
                log.debug('MISS - %s'%key)
                return self.__put(key,*opts)
        else:
            log.debug('Warning! cache key(%s) not reg!'%key)
    
    def __put(self,key,*opts):
        datakey=self.__sep.join(opts)
        ct,fc,rfc=self.__cache_config.get(key)
        if ct==CacheType.PARAMETER:
            v=self.__cache.setdefault(key,{})
            v[datakey]=fc(*opts)
            log.debug('FILL - %s(%s)'%(key,opts))
            return copy.deepcopy(self.__cache[key][datakey])
        else:
            self.__cache[key]=fc()
            log.debug('FILL - %s()'%key)
            return copy.deepcopy(self.__cache[key])

    # def __str__(self):
    #     return '%s=%s - func=%s - cache=%s'%(self.__cache_type,self.__cache_type.value,self.__func.__class__.__name__,self.__cache)
    
    def refresh(self):
        for k,v in self.__cache.items():
            ct,_,_=self.__cache_config.get(k)
            if ct==CacheType.PARAMETER:
                for mk,kv in v.items():
                    self.__put(k,*mk.split(self.__sep))
            else:
                self.__put(k)

    def get(self,key,*opts):
        return self.__get(key,*opts)

if __name__=='__main__':
    import random
    c=Cache('kkk',CacheType.PARAMETER,lambda x:[random.randint(1,10)])
    c.reg('ddd',CacheType.UN_PARAMETER,lambda:random.randint(1,10))
    print(c.get('kkk','a'),c.get('ddd','d'))
    print(c.get('kkk','a'),c.get('kkk','b'))
    c.refresh()
    print(c.get('kkk','a'),c.get('kkk','b'),c.get('ddd','d'))
    print(c.get('kkk','a'),c.get('kkk','b'),c.get('ddd','d'))

